package Radar;

import java.util.HashSet;
import java.util.concurrent.CopyOnWriteArraySet;

import Misil.*;
import Entorno.Entorno;
import Utilidades.Logger;

/**
 * @brief Clase que se encarga de la deteccion de los misiles presentes en el entorno.
 * 		  Dado que el Radar posee el Servidor de la conexion de sockets, se debe crear
 * 		  SI O SI al radar antes que al servidor, pues el servidor es el cliente.
 * @version 1.0
 * @created 17-jul-2012 09:08:55 p.m.
 */
public class Radar {
	//Campos de la clase Radar
	Tx conexion;
	private HashSet<Detectado> elementosDetectados;
	private HashSet<Detectado> elementosVistos;
	private Entorno entorno;

	/**
	 * @brief Constructor predeterminado. Requiere una referencia al entorno.
	 * @param entorno
	 */
	public Radar(Entorno entorno,int puerto){

		conexion = new Tx(puerto);
		elementosDetectados= new HashSet<Detectado>();
		elementosVistos= new HashSet<Detectado>();
		this.entorno=entorno;
		Logger.borrarLog(); //Borro el log viejo que no me sirve para nada
		
	}


	/**
	 * @brief Devuelve el tiempo actual del entorno (o tiempo de la simulacion)
	 * @return tiempo del entorno
	 */
	public int getCurrentTime(){
		return entorno.getTime();
	}


	/**	
	 * @brief Actualiza el conjunto de elementos vistos, el de elementos detectados
	 * 		  y devuelve la lista de elementos detectados.
	 * @return lista de elementos detectados.
	 */
	public HashSet<Detectado> scan(){
		CopyOnWriteArraySet<Misil> conjunto=entorno.getObjetosDelEntorno();
		for(Misil objeto: conjunto){
			int bandera=0;//bandera=0 significa que es la primera vez que se detecta => lo meto en elementosVistos con
			//la primer marca de tiempo.   bandera=1 significa que ya se detecto antes=> lo saco de elementosVistos y lo
			//meto en elementosDetectados. bandera=2 significa que ya fue detectado dos veces => no hago nada con este objeto.
			Detectado eliminame=new Detectado();
			
			//Este bucle for-each se fija si el actual objeto del conjunto que se analiza (actual objeto del entorno)
			//esta o no en el grupo de elementosVistos. Si es un elementoVisto, se lo agrega a los elementosDetectados.
			//Como ambos grupos son SET, si se agrega dos veces lo mismo no pasa nada. En el if se lo elimina.
			//Si es un elemento visto se pone la bandera en 1.
			for(Detectado yaVisto:elementosVistos){
				if(yaVisto.getMisil()==objeto){
					yaVisto.setMarcaTiempo2(entorno.getTime(),objeto.getPosition());
					elementosDetectados.add(yaVisto);
					eliminame=yaVisto;
					//elementosVistos.remove(yaVisto);
					bandera=1;
				}
			}
			//Si era un elemento del set de elementosVistos, como paso a los detectados, se lo elimina
			if(elementosVistos.contains(eliminame)){elementosVistos.remove(eliminame);}
			//Caso contrario, si pertenece a los elementosDetectados, se pone la bandera en 2 para no hacer nada.
			for(Detectado yaDetectado:elementosDetectados){
				if(yaDetectado.getMisil()==objeto&&bandera!=1){bandera=2;}
			}
			
			//Si no es detectado ni visto, es nuevo => lo agrego a los vistos y le pongo un ID
			if(bandera==0){
				Detectado nuevoDetectado=new Detectado(objeto,entorno.getTime());
				elementosVistos.add(nuevoDetectado);
				objeto.generarID();
				System.out.println("Primera Deteccion de: "+objeto.toString());
				Logger.escribir("["+entorno.getTime()+"]  Primera Deteccion de: "+objeto.toString());
			}
			else if(bandera==1){
				System.out.println("Segunda Deteccion de: "+objeto.toString());
				Logger.escribir("["+entorno.getTime()+"]  Segunda Deteccion de: "+objeto.toString());
				/*for(Detectado detectado:elementosDetectados){
					if(detectado.getMisil()==objeto) detectado.printDetectado();
				}*/
			}
			else if(bandera==2){
				objeto.setsigueEnElAireState();
				System.out.println("Sigue en el aire: "+objeto.toString());
				Logger.escribir("["+entorno.getTime()+"]  Sigue en el aire: "+objeto.toString());
			}
			
		}
		limpiarDestruidos();//Elimino los destruidos de la lista de detectados
		return elementosDetectados;
	}
	
	
	/**
	 * @brief Metodo que elimina a los detectados que ya fueron destruidos.
	 */
	private void limpiarDestruidos(){
		HashSet<Detectado> nuevosDetectados = new HashSet<Detectado>();
		for(Detectado elemento: elementosDetectados){
			if(!elemento.getMisil().getDestruido()){
				nuevosDetectados.add(elemento);
			}
		}
		elementosDetectados=nuevosDetectados;
	}
	
	
	/**
	 * @brief Metodo que devuelve un Set con todos los misiles enemigos detectados que tienen el
	 * 		  campo gonnaDie en false. Es decir, aquellos que no han sido marcados como objetivos
	 * 		  por misiles aliados.
	 * @return conjunto de misiles enemigos detectado que aun no han sido marcados como objetivo
	 */
	public HashSet<Detectado> getNuevosEnemigosDetectados(){
		HashSet<Detectado> nuevosEnemigosDetectados = new HashSet<Detectado>();
		for(Detectado detectado:elementosDetectados){
			if(!detectado.getMisil().getAlineacionBelica()){ //Si no es aliado
				MisilEnemigo misil = (MisilEnemigo) detectado.getMisil();
				if(!misil.getsigueEnElAireState()){ //Si aun no ha sido marcado como objetivo significa que es nuevo
					nuevosEnemigosDetectados.add(detectado);
				}
			}
		}
		return nuevosEnemigosDetectados;
	}
	
	/**
	 * @brief Metodo que muestra la lista de elementos detectados.
	 */
	public void mostrarListaDetectados(){
		for(Detectado objeto: elementosDetectados){
			System.out.println(objeto.getMisil().toString());
		}
	}
	
	
	/**
	 * @brief Metodo que devuelve la lista de elementos detectados.
	 * @return lista de elementos detectados.
	 */
	public HashSet<Detectado> getDetectados(){
		return elementosDetectados;
	}
	
	/**
	 * @brief Metodo que devuelve la lista de elementos vistos.
	 * @return lista de elementos vistos.
	 */
	public HashSet<Detectado> getVistos(){
		return elementosVistos;
	}

	
	/**
	 * @brief Envia por socket los detectados al servidor
	 */
	public void detectarYEnviar(){
		HashSet<Detectado> enviame = getNuevosEnemigosDetectados();
		conexion.enviarObjeto(enviame);
	}


}